package bean;

import java.util.*;

/**
 * @author letere
 * @create 2020-12-24 19:18
 */
public class Ant {
    private List<Integer> route = new ArrayList<Integer>(); //路线：记录蚂蚁行走的路线
    private Integer currentCity; //当前城市：记录蚂蚁当前所在城市的ID

    private List<Integer> citys = new ArrayList<Integer>(); //城市：记录需要行走的城市ID
    private double[][] pheromoneMatrix; //信息素矩阵
    private int[][] distanceMatrix; //距离矩阵

    private  int[][] timeMatrix; //时间矩阵

    //构造器
    public Ant(List<Integer> citys, double[][] pheromoneMatrix, int[][] distanceMatrix,int[][] timeMatrix) {
        this.citys = citys;
        this.pheromoneMatrix = pheromoneMatrix;
        this.distanceMatrix = distanceMatrix;
        this.timeMatrix = timeMatrix;
    }

    /**
     * 添加路线
     * @param cityId
     */
    private void addRoute(Integer cityId) {
        route.add(cityId); //路线中添加城市ID
        currentCity = cityId; //当前城市修改为城市ID
        citys.remove(cityId); //需要行走的城市移除城市ID
    }

    /**
     * 随机选择初始城市
     */
    private void randomSelectCity() {
        Random random = new Random();
        Integer cityId = random.nextInt(citys.size())+1;
        addRoute(cityId);
    }

    /**
     * 选择下一个城市
     */
    private void selectNextCity() {
        if(citys.size() == 1) {
            addRoute(citys.get(0));
            addRoute(route.get(0)); //路线添加最开始的城市
            return;
        }

        Double alpha = 1.0; //信息素因子权重
        Double beta  = 2.0; //路线距离权重
        Map<Integer, Double> molecules = new HashMap<Integer, Double>();

        //计算分子
        for (Integer city : citys) {
            //城市从1开始数，数组从0开始数，所以涉及数组都要‘-1’
            Double molecule = Math.pow(pheromoneMatrix[currentCity-1][city-1], alpha) * Math.pow(1.0 / distanceMatrix[currentCity-1][city-1], beta);
            molecules.put(city, molecule);
        }

        //计算分母
        Double totalMolecule = 0.0;
        for(Integer city : molecules.keySet()) {
            totalMolecule += molecules.get(city);
        }

        //轮盘赌选择下一个城市
        double random = Math.random();
        Double temp = 0.0;
        for(Integer city : molecules.keySet()) {
            temp += molecules.get(city) / totalMolecule;
            if(temp >= random) {
                addRoute(city);
                break;
            }
        }
    }

    /**
     * 蚂蚁开始旅行
     */
    public void tour() {
        int cityQuantity = citys.size();
        randomSelectCity();
        for(int i=0; i<cityQuantity; i++) {
            selectNextCity();
        }
    }

    /**
     * 获取路线
     * @return
     */
    public List<Integer> getRoute() {
        return route;
    }

    /**
    * 计算路线所需的时间
    * @return
    **/
    public Integer getRouteTime() {
        Integer time = 0;
        for(int i=0; i<route.size()-1; i++) {
            time += timeMatrix[route.get(i)-1][route.get(i+1)-1];
        }
        return time;
    }

    /**
     * 计算路线总距离
     * @return
     */
    public Integer getRouteLength() {
        Integer length = 0;
        for(int i=0; i<route.size()-1; i++) {
            length += distanceMatrix[route.get(i)-1][route.get(i+1)-1];
        }
        return length;
    }


}
